package com.nttuan.model.dao;

import android.content.ContentValues;
import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.nfc.Tag;
import android.util.Log;

import com.nttuan.model.DataBaseHelper;
import com.nttuan.model.dao.service.CategoryService;
import com.nttuan.model.dao.service.LocationService;
import com.nttuan.model.dao.service.TaskService;
import com.nttuan.model.entity.Alarm;
import com.nttuan.model.entity.Category;
import com.nttuan.model.entity.Clash;
import com.nttuan.model.entity.FreeTime;
import com.nttuan.model.entity.Location;
import com.nttuan.model.entity.Task;
import com.nttuan.mycalender.R;
import com.nttuan.util.Support;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * Created by NT Tuan on 10/22/2014.
 */
public class TaskDao implements TaskService {
    private DataBaseHelper db;
    private CategoryService categoryService;
    private LocationService locationService;
    private static TaskDao taskDao;

    public static TaskDao getInstance(Context context) {
        if (taskDao == null)
            taskDao = new TaskDao(context);
        return taskDao;
    }

    public TaskDao(Context context) {
        try {
            categoryService = CategoryDao.getInstance(context);
            locationService = LocationDao.getInstance(context);
            db = new DataBaseHelper(context);
        } catch (Exception e) {
        }
    }

    @Override
    public boolean leader(int taskId, int userId) {
       return false;
    }

    @Override
    public boolean updatePublicId(int taskId, int publicId) {
        db.openDataBase();
        ContentValues values = new ContentValues();
        values.put(Task.PUBLIC_ID, publicId);
        String whereClause = Task.TASK_ID + "=?";
        String[] whereArgs = {taskId + ""};
        boolean result = db.update(Task.TABLE_NAME, values, whereClause, whereArgs);
        db.close();
        return result;
    }

    @Override
    public List<Task> taskOfWeek(Date date, boolean isActive) {
        List<Task> result = new ArrayList<Task>();
        Calendar start =Calendar.getInstance();
        start.setTime(Support.startWeek(date));
        Date end = Support.endWeek(date);
        do{
            for(Task task: tasksAvailableOfDate(start.getTime(),isActive))
                result.add(task);
            start.add(Calendar.DATE, 1);
        }while(start.getTime().compareTo(end) != 0);
        return result;
    }

    @Override
    public Task taskByPublicId(int publicId) {
        db.openDataBase();
        String selection = Task.PUBLIC_ID + "=?";
        String[] where = {publicId + ""};
        Cursor cursor = db.select(true, Task.TABLE_NAME, null, selection, where, null);
        Task task =null;
        if (cursor != null)
            if (cursor.moveToNext()) {
                task = getItem(cursor);
            }
        db.close();
        return task;
    }

    @Override
    public boolean activeByPublicId(int publicId, boolean isActive) {
        db.openDataBase();
        ContentValues values = new ContentValues();
        values.put(Task.IS_ACTIVE, isActive);
        String whereClause = Task.PUBLIC_ID + "=?";
        String[] whereArgs = {publicId + ""};
        boolean result = db.update(Task.TABLE_NAME, values, whereClause, whereArgs);
        db.close();
        return result;
    }

    @Override
    public boolean removeByPublicId(int publicId) {
        db.openDataBase();
        String whereClause = Task.PUBLIC_ID + "=?";
        String[] whereArgs = {publicId + ""};
        boolean result = db.delete(Task.TABLE_NAME, whereClause, whereArgs);
        db.close();
        return result;
    }

    @Override
    public List<Task> tasks() {
        db.openDataBase();
        List<Task> result = new ArrayList<Task>();
        Cursor cursor = db.select(true, Task.TABLE_NAME, null, null, null, null);
        if (cursor != null)
            while (cursor.moveToNext())
                result.add(getItem(cursor));
        db.close();
        return result;
    }

    @Override
    public List<Task> tasks(boolean isActive) {
        db.openDataBase();
        List<Task> result = new ArrayList<Task>();
        String selection = Task.IS_ACTIVE + "=?";
        String[] where = {isActive ? "1" : "0"};
        Cursor cursor = db.select(true, Task.TABLE_NAME, null, selection, where, null);
        if (cursor != null)
            while (cursor.moveToNext())
                result.add(getItem(cursor));
        db.close();
        return result;
    }

    @Override
    public Task task(int taskId) {
        db.openDataBase();
        String selection = Task.TASK_ID + "=?";
        String[] where = {taskId + ""};
        Cursor cursor = db.select(true, Task.TABLE_NAME, null, selection, where, null);
        Task task =null;
        if (cursor != null)
            if (cursor.moveToNext()) {
                task = getItem(cursor);
            }
        db.close();
        return task;
    }

    @Override
    public int createNewId(Task task) {
        if(create(task))
            return newId();
        return 0;
    }
    @Override
    public int newId(){
        db.openDataBase();
        String[] column ={"max("+Task.TASK_ID+") as newId"};
        Cursor cursor = db.select(true,Task.TABLE_NAME,column,null,null,null);
        if(cursor != null)
            if (cursor.moveToNext()){
                db.close();
                return cursor.getInt(cursor.getColumnIndex("newId"));
            }
        return  1;
    }
    @Override
    public boolean create(Task task) {
        db.openDataBase();
        ContentValues values = new ContentValues();
        values.put(Task.TASK_NAME, task.getTaskName());
        values.put(Task.DATE_START, Support.toString(task.getStart()));
        values.put(Task.DATE_END, Support.toString(task.getEnd()));
        values.put(Task.DURING, task.getDuring());
        values.put(Task.REMIND, task.getRemind());
        values.put(Task.LEVEL, task.getLevel());
        values.put(Task.REPEAT, task.getRepeat());
        values.put(Task.NOTE, task.getNote());
        values.put(Task.IS_ACTIVE, task.isActive());
        values.put(Task.TIME_ZONE, task.getTimeZone());
        values.put(Task.PUBLIC_ID, task.getPublicId());
        values.put(Location.LOCATION_ID, task.getLocation().getLocationId());
        values.put(Category.CATEGORY_ID, task.getCategory().getCategoryId());
        boolean result = db.insert(Task.TABLE_NAME, values);
        db.close();
        return result;
    }

    @Override
    public boolean update(Task task) {
        db.openDataBase();
        String whereClause = Task.TASK_ID + "=?";
        String[] whereArgs = {task.getTaskId() + ""};
        ContentValues values = new ContentValues();
        values.put(Task.TASK_NAME, task.getTaskName());
        values.put(Task.DATE_START, Support.toString(task.getStart()));
        values.put(Task.DATE_END, Support.toString(task.getEnd()));
        values.put(Task.DURING, task.getDuring());
        values.put(Task.REMIND, task.getRemind());
        values.put(Task.LEVEL, task.getLevel());
        values.put(Task.REPEAT, task.getRepeat());
        values.put(Task.NOTE, task.getNote());
        values.put(Task.IS_ACTIVE, task.isActive());
        values.put(Task.TIME_ZONE, task.getTimeZone());
        values.put(Location.LOCATION_ID, task.getLocation().getLocationId());
        values.put(Category.CATEGORY_ID, task.getCategory().getCategoryId());
        boolean result = db.update(Task.TABLE_NAME, values, whereClause, whereArgs);
        db.close();
        return result;
    }

    @Override
    public boolean remove(int taskId) {
        db.openDataBase();
        String whereClause = Task.TASK_ID + "=?";
        String[] whereArgs = {taskId + ""};
        boolean result = db.delete(Task.TABLE_NAME, whereClause, whereArgs);
        db.close();
        return result;
    }

    @Override
    public boolean active(int taskId, boolean isActive) {
        db.openDataBase();
        ContentValues values = new ContentValues();
        values.put(Task.IS_ACTIVE, isActive);
        String whereClause = Task.TASK_ID + "=?";
        String[] whereArgs = {taskId + ""};
        boolean result = db.update(Task.TABLE_NAME, values, whereClause, whereArgs);
        db.close();
        return result;
    }



    @Override
    public List<Task> taskOfDate(Date date, boolean isActive) {
        db.openDataBase();
        List<Task> result = new ArrayList<Task>();
        Calendar c = Calendar.getInstance();
        String dateOfWeek = Support.dateOfWeek(date) + "";
        String sDate = Support.toString(date);
        String sActive = isActive ? "1" : "0";
        //   String selection = "((date("+Task.DATE_START+")=date(?) and repeat='') or (date('now')<=date("+Task.DATE_END+") and "+Task.REPEAT+" like ?)) and "+Task.IS_ACTIVE+" = ?";
        String selection = "((date(" + Task.DATE_START + ")=date(?) and repeat='') or (date(?)<=date(" + Task.DATE_END + ") and " + Task.REPEAT + " like ?)) and " + Task.IS_ACTIVE + " = ?";
        String[] where = {sDate, sDate, "%" + dateOfWeek + "%", sActive};
        String orderBy = Task.DATE_START;
        Cursor cursor = db.select(true, Task.TABLE_NAME, null, selection, where, orderBy);
        if (cursor != null) {
            Task task;
            while (cursor.moveToNext()) {
                result.add(getItem(cursor));
            }
        }
        db.close();
        return result;
    }



    @Override
    public List<Clash> getClash(Task task) {
        List<Clash> result = new ArrayList<Clash>();
        List<Task> res = null;
        List<Date> dates = new ArrayList<Date>();
        if (task.getRepeat().equals(""))
            dates.add(task.getStart());
        else {
            String[] arr = task.getRepeat().split(",");
            for (String dateOfWeek : arr)
                dates.add(Support.nextDate(task.getStart(), Integer.parseInt(dateOfWeek)));
        }
        Date start, end, checkEnd;
        for (Date checkStart : dates) {
            checkEnd = Support.addDateTime(checkStart, task.getDuring());
            if (checkStart.after(task.getEnd()))
                break;
            res = taskOfDate(checkStart, task.isActive());
            for (Task checkItem : res) {
                if (checkItem.getTaskId() == task.getTaskId())
                    continue;
                start = Support.sysDate(checkStart, checkItem.getStart());
                end = Support.sysDate(checkStart, Support.addDateTime(start, checkItem.getDuring()));
                if (checkEnd.before(start) || checkStart.after(end)) {
                    continue;
                } else {
                    result.add(new Clash(checkStart, checkItem));
                }
            }
        }
        return result;
    }
    @Override
    public List<Task> available(Date now, boolean isActive) {
        db.openDataBase();
        String dateOfWeek = Support.dateOfWeek(now)+"";
        Log.d("dateoffw", dateOfWeek+"");
        String sDate = Support.toString(now);
        String sActive = isActive ? "1":"0";
        List<Task> result = new ArrayList<Task>();
//        String selection = "((datetime(" + Task.DATE_START + ") >=datetime(?) and datetime(" + Task.DATE_END + ") >= datetime(?) and repeat='') or (datetime(?) <= datetime("+Task.DATE_START+") and datetime(?)<=datetime(" + Task.DATE_END + ") and " + Task.REPEAT + " like ?)) and " + Task.IS_ACTIVE + " = ?";
//        String[] where = {sDate, sDate,sDate,sDate, "%" + dateOfWeek + "%", sActive};
        String selection = "datetime(" + Task.DATE_START + ") >=datetime(?) and datetime(?) <= datetime(" + Task.DATE_END + ") and " + Task.IS_ACTIVE + " = ?";
        String[] where = {sDate, sDate, sActive};
        Cursor cursor = db.select(true, Task.TABLE_NAME, null, selection, where, null);
        if (cursor != null) {
            while (cursor.moveToNext()) {
                result.add(getItem(cursor));
            }
        }
        db.close();
        return result;
   }
    @Override
    public List<Alarm> getAlarm(Date currentDate) {
        List<Task> available = available(currentDate, true);
        List<Alarm> result = new ArrayList<Alarm>();
        Alarm alarm;
        Log.d("avaiable", available.size()+"");
        Date alarmAt = null;
        for(Task task:available){
            alarm = new Alarm();
            if(task.getRepeat().equals("")){ // none repeat
                alarmAt =Support.subDate(task.getStart(),task.getRemind());
                if(Support.equalDate(alarmAt, currentDate)) {
                    alarm.setAlarmAt(alarmAt); // ???
                    alarm.setTask(task);
                    result.add(alarm);
                }
            }else{ //  repeat
                String[] arrRepeat = task.getRepeat().split(",");
                Date checkDate;
                Date toDate = Calendar.getInstance().getTime();
                for(String dateOfWeek: arrRepeat){
                    Log.d("task check", task.getTaskName());
                    checkDate = Support.nextDate(task.getStart(),Integer.parseInt(dateOfWeek));
                    alarmAt = Support.subDate(checkDate, task.getRemind());
                    Log.d("check date", Support.toString(checkDate));
                    Log.d("alarm date", Support.toString(alarmAt));
                    Log.d("now date", Support.toString(currentDate));
                    if(Support.equalDate(alarmAt, currentDate)) {
                        Log.d("get","ok");
                        alarm.setAlarmAt(alarmAt); // ???
                        alarm.setTask(task);
                        result.add(alarm);
                        break;
                    }
                }
            }
        }
        return  result;
    }

    @Override
    public boolean createPublicId(int taskId, int publicId) {
        db.openDataBase();
        String whereClause = Task.TASK_ID + "=?";
        String[] whereArgs = {taskId + ""};
        ContentValues values = new ContentValues();
        values.put(Task.PUBLIC_ID, publicId);
        boolean result = db.update(Task.TABLE_NAME, values, whereClause, whereArgs);
        db.close();
        return result;
    }

    @Override
    public List<Task> tasksAvailableOfDate(Date date, boolean isActive) {
        db.openDataBase();
        List<Task> result = new ArrayList<Task>();
        Calendar c = Calendar.getInstance();
        String dateOfWeek = Support.dateOfWeek(date) + "";
        String sDate = Support.toString(date);
        String sActive = isActive ? "1" : "0";
        //String selection = "(date("+Task.DATE_START+")=date(?) or (date('now')>date("+Task.DATE_START+") and "+Task.REPEAT+" like ?)) and "+Task.IS_ACTIVE+" = ?";
        //   String selection = "((date("+Task.DATE_START+")=date(?) and repeat='') or (date('now')>=date("+Task.DATE_START+") and date('now')<=date("+Task.DATE_END+") and "+Task.REPEAT+" like ?)) and "+Task.IS_ACTIVE+" = ?";
        String selection = "(((date(" + Task.DATE_START + ")=date(?) and repeat='') or (date(?)>=date(" + Task.DATE_START + ") and date(?)<=date(" + Task.DATE_END + ") and " + Task.REPEAT + " like ?))) and " + Task.IS_ACTIVE + " = ?";
        String[] where = {sDate, sDate, sDate, "%" + dateOfWeek + "%", sActive};
        String orderBy = Task.DATE_START;
        Cursor cursor = db.select(true, Task.TABLE_NAME, null, selection, where, orderBy);
        if (cursor != null) {
            while (cursor.moveToNext()) {
                result.add(getItem(cursor));
            }
        }
        db.close();
        return result;
    }

    @Override
    public List<Task> comingTasks(Date date, boolean isActive) {
//        Date currentDate = Calendar.getInstance().getTime();
//        if(Support.equalDate(date, currentDate))
//            return tasksAvailableOfDate(date, isActive);
//        return taskOfDate(date, isActive);
        return tasksAvailableOfDate(date, isActive);
    }

    private Date sysDate(Date res, Date target, boolean isStartDate) {
        Date temp = new Date();
        temp.setDate(res.getDate());
        temp.setMonth(res.getMonth());
        temp.setYear(res.getYear());
        temp.setHours(target.getHours());
        if (isStartDate)
            temp.setMinutes(Support.goodNumber(target.getMinutes(), true));
        else
            temp.setMinutes(Support.goodNumber(target.getMinutes(), false));
        return temp;
    }

    @Override
    public List<FreeTime> freeTime(Context context, Date onDate, boolean isActive) {
        List<FreeTime> result = new ArrayList<FreeTime>();
        List<Task> listTask = tasksAvailableOfDate(onDate, isActive);
        Resources res = context.getResources();
        listTask.add(0, new Task(-1, res.getString(R.string.start_new_date), Support.startOfDate(onDate), 0));
        listTask.add(listTask.size(), new Task(-1, res.getString(R.string.end_date), Support.endOfDate(onDate), 0));
        Date start = null;
        Date end = null;
        Task previous = null;
        Task nextTask = null;
        for (int i = 0; i < listTask.size() - 1; i++) {
            previous = listTask.get(i);
            nextTask = listTask.get(i + 1);
            start = Support.addDateTime(previous.getStart(), previous.getDuring());
            end = nextTask.getStart();
            start = sysDate(onDate, start, true);
            end = sysDate(onDate, end, false);
            int duringFree = Support.subTime(start, end);
            if (duringFree > 9)
                result.add(new FreeTime(start, duringFree, previous, nextTask));
        }
        return result;
    }

    private Task getItem(Cursor cursor) {
        Task task = new Task();
        task.setTaskId(cursor.getInt(cursor.getColumnIndex(Task.TASK_ID)));
        task.setTaskName(cursor.getString(cursor.getColumnIndex(Task.TASK_NAME)));
        task.setStart(Support.toDateTime(cursor.getString(cursor.getColumnIndex(Task.DATE_START)), false));
        task.setEnd(Support.toDateTime(cursor.getString(cursor.getColumnIndex(Task.DATE_END)), false));
        task.setDuring(cursor.getInt(cursor.getColumnIndex(Task.DURING)));
        task.setRemind(cursor.getInt(cursor.getColumnIndex(Task.REMIND)));
        task.setLevel(cursor.getInt(cursor.getColumnIndex(Task.LEVEL)));
        task.setRepeat(cursor.getString(cursor.getColumnIndex(Task.REPEAT)));
        task.setNote(cursor.getString(cursor.getColumnIndex(Task.NOTE)));
        task.setPublicId(cursor.getInt(cursor.getColumnIndex(Task.PUBLIC_ID)));
        task.setActive(Support.toActive(cursor.getString(cursor.getColumnIndex(Task.IS_ACTIVE))));
        task.setTimeZone(cursor.getString(cursor.getColumnIndex(Task.TIME_ZONE)));
        Category category = categoryService.category(cursor.getInt(cursor.getColumnIndex(Category.CATEGORY_ID)));
        Location location = locationService.location(cursor.getInt(cursor.getColumnIndex(Location.LOCATION_ID)));
        task.setCategory(category);
        task.setLocation(location);
        return task;
    }
}
